/*
 * DBMS Core
 * Author: Nikolay A. Makarov
 */
#include ".\dbcore.h"
#include <time.h> //for tests
#include <sys/types.h>
#include <sys/timeb.h>

std::string dbcore::vectorToString(vector< vector<char *> > vector) {
	std::string result;
	result = "@";
	for( int col = 0; col < vector.size(); col ++) {
		if(col != vector.size() - 1) {
			result = result  + vector[col].back() +",";
		} else {
			result = result  + vector[col].back();
		}
	}
	for (int pos = 0; pos < vector.size(); pos++) {
		result = result + "{" + vector[pos][0] + "}";
	}
	
	if (!vector.empty()) {
		for ( int i = 1; i < vector[0].size() - 1; i++)
		{
			for ( int j = 0; j < vector.size(); j ++) {
				if ( vector[j][i] != NULL && strcmp(vector[j][i], "(null)") != 0) {
					result = result + "[" + vector[j][i] + "]";
				}				
			}	
		}
	
	}
	
	return result;
}

std::string dbcore::vectorToString(vector < vector<std::string> > vector) {
	std::string result;
	result = "@";
	for( int col = 0; col < vector.size(); col ++) {
		result = result  + vector[col].back() +",";
	}
	for (int pos = 0; pos < vector.size(); pos++) {
		result = result + "{" + vector[pos][0] + "}";
	}

	if (!vector.empty()) {
		for ( int i = 1; i < vector.at(0).size() - 1; i++)
		{
			for ( int j = 0; j < vector.size(); j ++)
			{				
				if ( (vector[j][i].empty() != TRUE) && (strcmp(vector[j][i].data(), "(null)") != 0)) {
					result = result + "[" + vector[j][i] + "]";					
				}				
			}			
		}
		
	}
	return result;
}

void dbcore::Insert (char* nameOfTable, vector<char*> data){
	datastore2 DS;
	DS.setDataToTable(nameOfTable, data);
}

// Delete from vector by table id(primary key)
void dbcore::Delete(char* nameOfTable, char* nameOfColumn, vector<std::string> idColumns) {
	vector < vector <char*> > resultAll;
	vector < vector <char*> > result;
	vector <char*> temp;
    datastore2 DS;
	resultAll = DS.getDataFromTable(nameOfTable);
	
	for(int col = 0; col < resultAll.size(); col++) {
		if(strcmp(resultAll[col].at(0), nameOfColumn) == 0) {
			for(int j = 1; j < resultAll[col].size() - 1; j++) {
				if(resultAll[col].at(j) != NULL) {
					for(int idPos = 0; idPos < idColumns.size(); idPos++) {
						if(strcmp(resultAll[col].at(j), idColumns.at(idPos).data()) == 0) {
							//Delete item
							for(int row = 0; row < resultAll.size(); row++) {
								resultAll[row].at(j) = NULL;
							}
							break;
						}
					}
				}
			}
		}
	}
	
	for ( int i = 0; i < resultAll.size(); i++)
	{
		for( int j = 0; j < resultAll[0].size()-1; j++)
		{
			if(resultAll[i][j] != NULL)
			{
				temp.push_back(resultAll[i][j]);
			}
		}
		result.push_back(temp);
		temp.clear();
	}
	
	
	DS.refreshDataToTable(nameOfTable, result);
}

void dbcore::Update(char* nameOfTable, char* nameOfColumn, vector<std::string> idColumns, char* updateColumn, char* value) {	
	vector < vector <char*> > resultAll;
	vector < vector <char*> > result;
	vector <char*> temp;
	datastore2 DS;
	resultAll = DS.getDataFromTable(nameOfTable);
	for(int col = 0; col < resultAll.size(); col++) {
		if(strcmp(nameOfColumn, resultAll[col].at(0)) == 0) {
			for(int j = 1; j < resultAll[col].size() - 1; j++) {
				if(resultAll[col].at(j) != NULL) {
					for(int idPos = 0; idPos < idColumns.size(); idPos++) {
						if(resultAll[col].at(j) == idColumns.at(idPos)) {
							//we find item, now we must find row for update
							for(int row = 0; row < resultAll.size(); row++) {
								if(strcmp(resultAll[row].at(0), updateColumn) == 0) {
									resultAll[row][j] = value;
								}
							}
						}
					}
				}
			}
		}
	}

  	for ( int i = 0; i < resultAll.size(); i++)
	{
		for( int j = 0; j < resultAll[i].size()-1; j++)
		{
			if(resultAll[i][j] != NULL)
			{
				temp.push_back(resultAll[i][j]);
			}
		}
		result.push_back(temp);
		temp.clear();
	}
	DS.refreshDataToTable(nameOfTable, result);
}

vector< vector<char*> > dbcore::Select(char* nameOfTable){
	vector< vector<char*> > resultAll;
	datastore2 DS;
	resultAll  = DS.getDataFromTable(nameOfTable);
	return resultAll;
}

vector< vector<char*> > dbcore::Select(vector< vector<char*> > resultAll, vector<char*> nameOfColumn, vector<char*> operand, vector<char*> value) {
	vector < vector <char*> > result;
	vector <char*> temp;
   //	datastore2 DS;
	for ( int col = 0; col < nameOfColumn.size(); col++) {
		for(int name = 0; name < resultAll.size(); name++) {
			if (strcmp(nameOfColumn[col],resultAll[name][0])==0) {
				for(int j = 1; j<resultAll[name].size(); j++) {
					if(resultAll[name][j] != NULL) {
						if(strcmp(resultAll[name][j],value[col])!=0) {
							for(int h =0; h < resultAll.size(); h++) {
								resultAll[h][j]=NULL;
							}
						}
					}
				}
			}
		}
    }

	for ( int i = 0; i < resultAll.size(); i++)
	{
		for( int j = 0; j < resultAll[0].size(); j++)
		{
			if(resultAll[i][j] != NULL)
			{
				temp.push_back(resultAll[i][j]);
			}
		}
		result.push_back(temp);
		temp.clear();
	}
	return result;
}

vector< vector<char*> > dbcore::Select (char* nameOfTable, vector <char*> nameOfColumn, vector <char*> operand, vector<char*> value)
{
	vector < vector <char*> > resultAll;
	vector < vector <char*> > result;
	vector <char*> temp;
   	datastore2 DS;
	resultAll = DS.getDataFromTable(nameOfTable);
	for ( int col = 0; col < nameOfColumn.size(); col++)
	{
		for(int name = 0; name < resultAll.size(); name++)
		{
			if (strcmp(nameOfColumn[col],resultAll[name][0])==0)
			{
				for(int j = 1; j<resultAll[name].size(); j++)
				{
					if(resultAll[name][j] != NULL)
					{
						if(strcmp(resultAll[name][j],value[col])!=0)
						{
							for(int h =0; h < resultAll.size();h++)
							{
								resultAll[h][j] = NULL;
							}
						}
					}
				}
			}
		}
    }

	for ( int i = 0; i < resultAll.size(); i++)
	{
		for( int j = 0; j < resultAll[0].size(); j++)
		{
			if(resultAll[i][j] != NULL)
			{
				temp.push_back(resultAll[i][j]);
			}
		}
		result.push_back(temp);
		temp.clear();
	}
	return result;
}

vector < vector<char*> > dbcore::Select(vector < vector<char*> > resultTable, char* nameOfColumn1, char* nameOfColumn2) {
	vector < vector<char*> > result;
	vector <char*> temp1;
	vector <char*> temp2;

	//Search two idintifical columns and copy to temp1 and temp 2 vectors
	for(int col = 0; col < resultTable.size(); col++) {
		if (strcmp(resultTable[col][0], nameOfColumn1) == 0) {
			temp1 = resultTable[col];
			for (int col2 = col; col2 < resultTable.size(); col2++) {
				if (strcmp(resultTable[col2][0], nameOfColumn2) == 0) {
					temp2 = resultTable[col2];
				}
			}
			break;
		}		 
	}
	//Compare two values and copy rows to result table if values are identifical
	for(int pos = 1; pos < temp1.size(); pos++) {
		if (strcmp(temp1.at(pos), temp2.at(pos)) != 0) {
			for(int i = 0; i < resultTable.size(); i++) {
				resultTable[i][pos] = NULL;
				
			}
		}
	}

	//Make result. Check for "NULL"
	vector<char*> temp;
	for ( int i = 0; i < resultTable.size(); i++)
	{
		for( int j = 0; j < resultTable[0].size(); j++)
		{
			if(resultTable[i][j] != NULL) {
				temp.push_back(resultTable[i][j]);
			}
		}
		result.push_back(temp);
		temp.clear();
	}
	
	return result;
}

//Select for some columns
vector < vector<std::string> > dbcore::Select(vector < vector<std::string> > resultTable, vector<char*> namesOfColumns) {
	vector< vector<std::string> > result;
	for (int i = 0; i < namesOfColumns.size(); i++) {
		for (int col = 0; col < resultTable.size(); col++) {
			
			if (resultTable[col][0] == namesOfColumns.at(i)) {
				result.push_back(resultTable.at(col));
			}
		}
	}
	return result;
}

vector < vector<char*> > dbcore::superJoin(vector<char*> tablesList, vector< vector<char*> > joinVector) {
	vector< vector<char*> > joinTable;
	datastore2 DS;
	
	if (joinVector.size() == 0) {
		joinVector = DS.getDataFromTable(tablesList.back());
		tablesList.pop_back();
	}
	if ( tablesList.size() != 0 ) {
		joinTable = this->Join(DS.getDataFromTable(tablesList.back()), joinVector, tablesList.back());
		tablesList.pop_back();
		return superJoin(tablesList, joinTable);
	} else {
		
		return joinVector;
	}
}

vector < vector<char*> > dbcore::Join(vector < vector<char*> > resultTable1, vector < vector<char*> > resultTable2, char* tableName){
	
	vector < vector<char*> > result;
	
	datastore2 DS;
	vector <char*> tempLine;

	// Get column`s description(names) for JOIN table
	for (int i = 0; i < resultTable1.size(); i++) {
		tempLine.push_back(resultTable1[i].at(0));
		result.push_back(tempLine);
		tempLine.clear();
	
	}
	for (int j = 0; j < resultTable2.size(); j++) {
		tempLine.push_back(resultTable2[j].at(0));
		result.push_back(tempLine);
		tempLine.clear();
	}
	int table1Size = 1;
	int table2Size = 1;
	tempLine.clear();

	
	for (int col = 0; col < result.size(); col++) {
		if (col < resultTable1.size()) {
			//Set data to JOIN-result from first table
			for (int i = 1; i < resultTable1[col].size() - 1; i++) {
				for (int j = 0; j < countVector (resultTable2[0]) - 1; j++) {	
						if (resultTable1[col].at(i) != NULL) result[col].push_back(resultTable1[col].at(i));
				}
			}
		} else {
			//Set data to JOIN-result from second table
			int position = 1;
			int positionInVector = 1;
		
			for ( int i = 0; i < (resultTable1[0].size() - 2)*(resultTable2[0].size() - 2); i++) {
				if (position < resultTable2[0].size() - 1) {
					if (resultTable2[col-resultTable1.size()].at(position) != NULL) result[col].push_back(resultTable2[col-resultTable1.size()].at(position));
					positionInVector++;
					position++;
				}  else {
					position = 1;
					if (resultTable2[col-resultTable1.size()].at(position) != NULL) result[col].push_back(resultTable2[col-resultTable1.size()].at(position));
					positionInVector++;
					position++;
				}
			}
		}
	}

	// Get column`s types for JOIN table
	int table1_Size = resultTable1.size();
	for (int i = 0; i <table1_Size; i++) {
		result[i].push_back(resultTable1[i].back());
	}
	
	for (int j = 0; j < resultTable2.size(); j++) {
		result[j + table1_Size].push_back(resultTable2[j].back());
	}

	
	return result;
}
int dbcore::countVector(vector<char*> vector) {
	int count  = 0;
	for (int i = 0; i < vector.size(); i++) {
		if (vector.at(i) != NULL) {
			count++;
		}
	}
	return  count-1;
}
char* dbcore::getColumnType(char* nameOfTable, char* nameOfColumn) {
	char* typeName;
	datastore2 DS;
	typeName = DS.getColumnType(nameOfTable, nameOfColumn);
	return typeName;
}
std::string dbcore::getColumnTypeString(char* nameOfTable, char* nameOfColumn) {
	std::string typeName;
	datastore2 DS;
	typeName = DS.getColumnType(nameOfTable, nameOfColumn);
	return typeName;

}